﻿Imports Microsoft.Win32
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization
Imports System.Drawing
Imports System.Globalization
Imports System.IO
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Text
Imports System.Windows.Forms
Imports System.Windows.Forms.Design
Imports System.Workflow.ComponentModel.Serialization
Imports System.Xml

Namespace System.Workflow.ComponentModel.Design
    Public NotInheritable Class WorkflowTheme
        Implements IDisposable
        ' Events
        Public Shared Custom Event ThemeChanged As EventHandler

        ' Methods
        Shared Sub New()
            WorkflowTheme.currentTheme = WorkflowTheme.LoadThemeSettingFromRegistry
            If (Not WorkflowTheme.currentTheme Is Nothing) Then
                WorkflowTheme.currentTheme.ReadOnly = True
            End If
        End Sub

        Public Sub New()
            Me.filePath = WorkflowTheme.GenerateThemeFilePath
            If ((Not Me.filePath Is Nothing) AndAlso (Me.filePath.Length > 0)) Then
                Me.name = Path.GetFileNameWithoutExtension(Me.filePath)
            End If
        End Sub

        Friend Sub AmbientPropertyChanged(ByVal ambientProperty As AmbientProperty)
            Dim theme As DesignerTheme
            For Each theme In Me.designerThemes
                Dim readOnly As Boolean = Me.ReadOnly
                Me.ReadOnly = False
                theme.OnAmbientPropertyChanged(ambientProperty)
                Me.ReadOnly = [readOnly]
            Next
        End Sub

        Public Function Clone() As WorkflowTheme
            Dim theme As WorkflowTheme = Nothing
            Dim serializationManager As New DesignerSerializationManager
            [Using] serializationManager.CreateSession
                Dim provider As New ThemeSerializationProvider
                Dim output As New StringWriter(New StringBuilder, CultureInfo.InvariantCulture)
                Dim input As StringReader = Nothing
                Try 
                    DirectCast(serializationManager, IDesignerSerializationManager).AddSerializationProvider(provider)
                    Dim serializer As New WorkflowMarkupSerializer
                    [Using] writer2 As XmlWriter = Helpers.CreateXmlWriter(output)
                        serializer.Serialize(serializationManager, writer2, Me)
                    End [Using]
                    input = New StringReader(output.ToString)
                    [Using] reader2 As XmlReader = XmlReader.Create(input)
                        theme = [TryCast](serializer.Deserialize(serializationManager, reader2),WorkflowTheme)
                    End [Using]
                Finally
                    DirectCast(serializationManager, IDesignerSerializationManager).RemoveSerializationProvider(provider)
                    input.Close
                    output.Close
                End Try
            End [Using]
            If (Not theme Is Nothing) Then
                theme.filePath = Me.filePath
                Dim theme2 As DesignerTheme
                For Each theme2 In theme.DesignerThemes
                    theme2.Initialize
                Next
            End If
            Return theme
        End Function

        Public Shared Function CreateStandardTheme(ByVal standardThemeType As ThemeType) As WorkflowTheme
            Dim theme As WorkflowTheme = Nothing
            If (standardThemeType = ThemeType.Default) Then
                theme = New WorkflowTheme
                theme.AmbientTheme.UseDefaultFont
            ElseIf (standardThemeType = ThemeType.System) Then
                theme = New WorkflowTheme { _
                    .AmbientTheme = { UseOperatingSystemSettings:=True } _
                }
            Else
                Return Nothing
            End If
            Dim strArray As String() = WorkflowTheme.StandardThemes.Item(standardThemeType)
            If (Not strArray Is Nothing) Then
                theme.Name = strArray(0)
                theme.themeType = standardThemeType
                theme.Description = strArray(1)
                theme.FilePath = WorkflowTheme.LookupPath
            End If
            Return theme
        End Function

        Private Sub Dispose(ByVal disposing As Boolean)
            Dim theme As DesignerTheme
            For Each theme In Me.designerThemes
                DirectCast(theme, IDisposable).Dispose
            Next
            Me.designerThemes.Clear
        End Sub

        Protected Overrides Sub Finalize()
            Try 
                Me.Dispose(False)
            Finally
                MyBase.Finalize
            End Try
        End Sub

        Friend Shared Sub FireThemeChange()
            If (Not WorkflowTheme.ThemeChanged Is Nothing) Then
                WorkflowTheme.ThemeChanged.Invoke(WorkflowTheme.currentTheme, EventArgs.Empty)
            End If
        End Sub

        Public Shared Function GenerateThemeFilePath() As String
            Dim lookupPath As String = WorkflowTheme.LookupPath
            Dim path As String = Path.Combine(lookupPath, (DR.GetString("MyFavoriteTheme", New Object(0  - 1) {}) & ".wtm"))
            Dim i As Integer = 1
            Do While File.Exists(path)
                path = Path.Combine(lookupPath, (DR.GetString("MyFavoriteTheme", New Object(0  - 1) {}) & i.ToString(CultureInfo.InvariantCulture) & ".wtm"))
                i += 1
            Loop
            Return path
        End Function

        Friend Shared Function GetDefaultFont() As Font
            If (WorkflowTheme.defaultFont Is Nothing) Then
                If (Not WorkflowTheme.UIService Is Nothing) Then
                    WorkflowTheme.defaultFont = [TryCast](WorkflowTheme.UIService.Styles.Item("DialogFont"),Font)
                End If
                If (WorkflowTheme.defaultFont Is Nothing) Then
                    WorkflowTheme.defaultFont = Control.DefaultFont
                End If
            End If
            Return WorkflowTheme.defaultFont
        End Function

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public Function GetDesignerTheme(ByVal designer As ActivityDesigner) As ActivityDesignerTheme
            If (designer Is Nothing) Then
                Throw New ArgumentNullException("designer")
            End If
            Return [TryCast](Me.GetTheme(designer.GetType),ActivityDesignerTheme)
        End Function

        Friend Function GetTheme(ByVal designerType As Type) As DesignerTheme
            Dim readOnly As Boolean = Me.ReadOnly
            Dim item As DesignerTheme = If(Me.designerThemes.Contains(designerType.FullName), Me.designerThemes.Item(designerType.FullName), Nothing)
            Try 
                Me.ReadOnly = False
                If ((item Is Nothing) OrElse ((Not item.DesignerType Is Nothing) AndAlso Not designerType.Equals(item.DesignerType))) Then
                    Dim flag2 As Boolean = (Not item Is Nothing)
                    Dim attribute As ActivityDesignerThemeAttribute = [TryCast](TypeDescriptor.GetAttributes(designerType).Item(GetType(ActivityDesignerThemeAttribute)),ActivityDesignerThemeAttribute)
                    If (attribute Is Nothing) Then
                        Throw New InvalidOperationException(DR.GetString("Error_ThemeAttributeMissing", New Object() { designerType.FullName }))
                    End If
                    If (attribute.DesignerThemeType Is Nothing) Then
                        Throw New InvalidOperationException(DR.GetString("Error_ThemeTypeMissing", New Object() { designerType.FullName }))
                    End If
                    If (attribute.Xml.Length > 0) Then
                        Dim manifestResourceStream As Stream = designerType.Assembly.GetManifestResourceStream(designerType, attribute.Xml)
                        If (manifestResourceStream Is Nothing) Then
                            manifestResourceStream = designerType.Assembly.GetManifestResourceStream(("System.Workflow.ComponentModel.Design.ActivityDesignerThemes." & attribute.Xml))
                        End If
                        Dim reader As XmlReader = If((Not manifestResourceStream Is Nothing), XmlReader.Create(manifestResourceStream), Nothing)
                        If (reader Is Nothing) Then
                            reader = XmlReader.Create(New StringReader(attribute.Xml))
                        End If
                        If (Not reader Is Nothing) Then
                            Dim serializationManager As New DesignerSerializationManager
                            [Using] serializationManager.CreateSession
                                Dim provider As New ThemeSerializationProvider
                                Try 
                                    DirectCast(serializationManager, IDesignerSerializationManager).AddSerializationProvider(provider)
                                    DirectCast(serializationManager, IDesignerSerializationManager).Context.Push(Me)
                                    Dim serializer As New WorkflowMarkupSerializer
                                    item = [TryCast](serializer.Deserialize(serializationManager, reader),DesignerTheme)
                                    If ((Not item Is Nothing) AndAlso Not attribute.DesignerThemeType.IsAssignableFrom(item.GetType)) Then
                                        DirectCast(serializationManager, IDesignerSerializationManager).ReportError(New WorkflowMarkupSerializationException(DR.GetString("ThemeTypesMismatch", New Object() { attribute.DesignerThemeType.FullName, item.GetType.FullName })))
                                        item = Nothing
                                    End If
                                    If (serializationManager.Errors.Count > 0) Then
                                        Dim str As String = String.Empty
                                        Dim obj2 As Object
                                        For Each obj2 In serializationManager.Errors
                                            str = (str & obj2.ToString & "\n")
                                        Next
                                    End If
                                Finally
                                    DirectCast(serializationManager, IDesignerSerializationManager).RemoveSerializationProvider(provider)
                                    reader.Close
                                End Try
                            End [Using]
                        End If
                    End If
                    If (item Is Nothing) Then
                        Try 
                            item = [TryCast](Activator.CreateInstance(attribute.DesignerThemeType, New Object() { Me }),DesignerTheme)
                        Catch obj1 As Object
                            item = New ActivityDesignerTheme(Me)
                        End Try
                    End If
                    item.DesignerType = designerType
                    item.ApplyTo = designerType.FullName
                    item.Initialize
                    If flag2 Then
                        Me.designerThemes.Remove(designerType.FullName)
                    End If
                    Me.designerThemes.Add(item)
                End If
                If (item.DesignerType Is Nothing) Then
                    item.DesignerType = designerType
                End If
            Finally
                Me.ReadOnly = [readOnly]
            End Try
            Return item
        End Function

        Public Shared Function Load(ByVal themeFilePath As String) As WorkflowTheme
            Dim serializationManager As New DesignerSerializationManager
            [Using] serializationManager.CreateSession
                Return WorkflowTheme.Load(serializationManager, themeFilePath)
            End [Using]
        End Function

        Public Shared Function Load(ByVal serializationManager As IDesignerSerializationManager, ByVal themeFilePath As String) As WorkflowTheme
            If (serializationManager Is Nothing) Then
                Throw New ArgumentNullException("serializationManager")
            End If
            Dim theme As WorkflowTheme = Nothing
            If ((Not themeFilePath Is Nothing) AndAlso File.Exists(themeFilePath)) Then
                Dim reader As XmlReader = XmlReader.Create(themeFilePath)
                Dim provider As New ThemeSerializationProvider
                Try 
                    serializationManager.AddSerializationProvider(provider)
                    Dim serializer As New WorkflowMarkupSerializer
                    theme = [TryCast](serializer.Deserialize(serializationManager, reader),WorkflowTheme)
                Finally
                    serializationManager.RemoveSerializationProvider(provider)
                    reader.Close
                End Try
                If (Not theme Is Nothing) Then
                    theme.filePath = themeFilePath
                End If
            End If
            Return theme
        End Function

        Public Shared Function LoadThemeSettingFromRegistry() As WorkflowTheme
            Dim theme As WorkflowTheme = Nothing
            Dim key As RegistryKey = Registry.CurrentUser.OpenSubKey(WorkflowTheme.RegistryKeyPath)
            If (Not key Is Nothing) Then
                Dim standardThemeType As ThemeType = ThemeType.Default
                Try 
                    Dim obj2 As Object = key.GetValue("ThemeType")
                    If TypeOf obj2 Is String Then
                        standardThemeType = DirectCast(Enum.Parse(GetType(ThemeType), CStr(obj2), True), ThemeType)
                    End If
                    If (standardThemeType = ThemeType.UserDefined) Then
                        obj2 = key.GetValue("ThemeFilePath")
                        Dim path As String = If(TypeOf obj2 Is String, CStr(obj2), String.Empty)
                        If (File.Exists(path) AndAlso Path.GetExtension(path).Equals("*.wtm".Replace("*", ""), StringComparison.Ordinal)) Then
                            theme = WorkflowTheme.Load(path)
                        End If
                    End If
                Catch obj1 As Object
                Finally
                    If (theme Is Nothing) Then
                        If (standardThemeType = ThemeType.UserDefined) Then
                            standardThemeType = ThemeType.Default
                        End If
                        theme = WorkflowTheme.CreateStandardTheme(standardThemeType)
                    End If
                    key.Close
                End Try
            End If
            Return theme
        End Function

        Public Sub Save(ByVal themeFilePath As String)
            If ((themeFilePath Is Nothing) OrElse (themeFilePath.Length = 0)) Then
                Throw New ArgumentException(DR.GetString("ThemePathNotValid", New Object(0  - 1) {}), "themeFilePath")
            End If
            Dim manager As New DesignerSerializationManager
            [Using] manager.CreateSession
                Dim serializationManager As New WorkflowMarkupSerializationManager(manager)
                Dim writer As XmlWriter = Nothing
                Dim provider As New ThemeSerializationProvider
                Try 
                    Dim directoryName As String = Path.GetDirectoryName(themeFilePath)
                    If ((directoryName.Length > 0) AndAlso Not Directory.Exists(directoryName)) Then
                        Directory.CreateDirectory(directoryName)
                    End If
                    writer = Helpers.CreateXmlWriter(themeFilePath)
                    serializationManager.AddSerializationProvider(provider)
                    New WorkflowMarkupSerializer().Serialize(serializationManager, writer, Me)
                Finally
                    serializationManager.RemoveSerializationProvider(provider)
                    If (Not writer Is Nothing) Then
                        writer.Close
                    End If
                End Try
                Me.filePath = themeFilePath
            End [Using]
        End Sub

        Public Shared Sub SaveThemeSettingToRegistry()
            Dim key As RegistryKey = Registry.CurrentUser.CreateSubKey(WorkflowTheme.RegistryKeyPath)
            If (Not key Is Nothing) Then
                Try 
                    key.SetValue("ThemeType", WorkflowTheme.CurrentTheme.themeType)
                    If (WorkflowTheme.CurrentTheme.themeType = ThemeType.UserDefined) Then
                        key.SetValue("ThemeFilePath", WorkflowTheme.CurrentTheme.FilePath)
                    Else
                        key.SetValue("ThemeFilePath", String.Empty)
                    End If
                Catch obj1 As Object
                Finally
                    key.Close
                End Try
            End If
        End Sub

        Private Sub System.IDisposable.Dispose() Implements IDisposable.Dispose
            Me.Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub


        ' Properties
        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public ReadOnly Property AmbientTheme As AmbientTheme
            Get
                Return [TryCast](Me.GetTheme(GetType(WorkflowView)),AmbientTheme)
            End Get
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public ReadOnly Property ContainingFileDirectory As String
            Get
                Dim str As String = String.Empty
                If (Me.filePath.Length > 0) Then
                    Try 
                        str = (Path.GetDirectoryName(Me.filePath) & Path.DirectorySeparatorChar)
                    Catch obj1 As Object
                    End Try
                End If
                Return str
            End Get
        End Property

        Public Shared Property CurrentTheme As WorkflowTheme
            Get
                If (WorkflowTheme.currentTheme Is Nothing) Then
                    WorkflowTheme.currentTheme = WorkflowTheme.CreateStandardTheme(ThemeType.Default)
                    WorkflowTheme.currentTheme.ReadOnly = True
                End If
                Return WorkflowTheme.currentTheme
            End Get
            Set(ByVal value As WorkflowTheme)
                If (Not WorkflowTheme.currentTheme Is value) Then
                    If (value Is Nothing) Then
                        Throw New ArgumentNullException("value")
                    End If
                    Dim currentTheme As WorkflowTheme = WorkflowTheme.currentTheme
                    WorkflowTheme.currentTheme = value
                    WorkflowTheme.currentTheme.ReadOnly = True
                    If WorkflowTheme.EnableChangeNotification Then
                        If (Not currentTheme Is Nothing) Then
                            DirectCast(currentTheme, IDisposable).Dispose
                            currentTheme = Nothing
                        End If
                        WorkflowTheme.FireThemeChange
                    End If
                End If
            End Set
        End Property

        Public Property Description As String
            Get
                Return Me.description
            End Get
            Set(ByVal value As String)
                If Me.ReadOnly Then
                    Throw New InvalidOperationException(DR.GetString("ThemePropertyReadOnly", New Object(0  - 1) {}))
                End If
                Me.description = value
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
        Public ReadOnly Property DesignerThemes As IList
            Get
                Return Me.designerThemes
            End Get
        End Property

        Public Shared Property EnableChangeNotification As Boolean
            Get
                Return WorkflowTheme.enableChangeNotification
            End Get
            Set(ByVal value As Boolean)
                If (WorkflowTheme.enableChangeNotification <> value) Then
                    WorkflowTheme.enableChangeNotification = value
                End If
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(False)> _
        Public Property FilePath As String
            Get
                Return Me.filePath
            End Get
            Set(ByVal value As String)
                If Me.ReadOnly Then
                    Throw New InvalidOperationException(DR.GetString("ThemePropertyReadOnly", New Object(0  - 1) {}))
                End If
                Me.filePath = value
            End Set
        End Property

        Public Shared ReadOnly Property LookupPath As String
            Get
                Dim folderPath As String = String.Empty
                Try 
                    folderPath = Environment.GetFolderPath(SpecialFolder.ApplicationData)
                    If String.IsNullOrEmpty(folderPath) Then
                        folderPath = New Uri(Assembly.GetExecutingAssembly.CodeBase).AbsolutePath
                    End If
                    folderPath = Path.Combine(folderPath, ("Windows Workflow Foundation" & Path.DirectorySeparatorChar & "Themes"))
                    folderPath = (folderPath & Path.DirectorySeparatorChar)
                Catch obj1 As Object
                End Try
                Return folderPath
            End Get
        End Property

        Public Property Name As String
            Get
                Return Me.name
            End Get
            Set(ByVal value As String)
                If Me.ReadOnly Then
                    Throw New InvalidOperationException(DR.GetString("ThemePropertyReadOnly", New Object(0  - 1) {}))
                End If
                Me.name = value
            End Set
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public Property [ReadOnly] As Boolean
            Get
                Return Me.readOnly
            End Get
            Set(ByVal value As Boolean)
                Me.readOnly = value
            End Set
        End Property

        Public Shared ReadOnly Property RegistryKeyPath As String
            Get
                Return (DesignerHelpers.DesignerPerUserRegistryKey & "\" & WorkflowTheme.WorkflowThemesSubKey)
            End Get
        End Property

        Public Shared ReadOnly Property StandardThemes As IDictionary([Of] ThemeType, String())
            Get
                Dim dictionary As New Dictionary([Of] ThemeType, String())
                dictionary.Add(ThemeType.Default, New String() { DR.GetString("DefaultTheme", New Object(0  - 1) {}), DR.GetString("DefaultThemeDescription", New Object(0  - 1) {}) })
                dictionary.Add(ThemeType.System, New String() { DR.GetString("OSTheme", New Object(0  - 1) {}), DR.GetString("SystemThemeDescription", New Object(0  - 1) {}) })
                Return dictionary
            End Get
        End Property

        <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
        Public ReadOnly Property Type As ThemeType
            Get
                Return Me.themeType
            End Get
        End Property

        Friend Shared Property UIService As IUIService
            Get
                Return WorkflowTheme.uiService
            End Get
            Set(ByVal value As IUIService)
                WorkflowTheme.uiService = value
                WorkflowTheme.defaultFont = Nothing
                WorkflowTheme.CurrentTheme.AmbientTheme.UpdateFont
            End Set
        End Property

        Public Property Version As String
            Get
                Return Me.version
            End Get
            Set(ByVal value As String)
                If Me.ReadOnly Then
                    Throw New InvalidOperationException(DR.GetString("ThemePropertyReadOnly", New Object(0  - 1) {}))
                End If
                Me.version = value
            End Set
        End Property


        ' Fields
        Private Shared currentTheme As WorkflowTheme = Nothing
        Private Shared defaultFont As Font = Nothing
        Friend Shared DefaultNamespace As String = GetType(WorkflowTheme).Namespace.Replace(".", "_")
        Friend Const DefaultThemeFileExtension As String = "*.wtm"
        Private description As String = DR.GetString("DefaultThemeDescription", New Object(0  - 1) {})
        Private designerThemes As ThemeCollection = New ThemeCollection
        Private Shared enableChangeNotification As Boolean = True
        Private filePath As String = String.Empty
        Private name As String = String.Empty
        Private [readOnly] As Boolean
        Private Const ThemePathKey As String = "ThemeFilePath"
        Private Const ThemeResourceNS As String = "System.Workflow.ComponentModel.Design.ActivityDesignerThemes."
        Private themeType As ThemeType = ThemeType.UserDefined
        Private Const ThemeTypeKey As String = "ThemeType"
        Private Shared uiService As IUIService = Nothing
        Private version As String = "1.0"
        Private Shared ReadOnly WorkflowThemesSubKey As String = "Themes"

        ' Nested Types
        Private Class ThemeCollection
            Inherits KeyedCollection([Of] String, DesignerTheme)
            ' Methods
            Protected Overrides Function GetKeyForItem(ByVal item As DesignerTheme) As String
                Return item.ApplyTo
            End Function

        End Class
    End Class
End Namespace

